package indi.fritz.bigmap;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import indi.fritz.bigmap.util.RandomString;
import indi.fritz.bigmap.volme.DiskEngine;
import indi.fritz.bigmap.volme.Engine;

public class Test {
	
	static String path = "E:\\tmp\\mapdb";
	

	public static void main(String[] args) throws Exception {
		test();
		bigTest();
		delete();
		iterator();
		read();
		rebuild();
		int i = 20;
		while(i-->0) {
			threadTest();
		}
	}
	
	private static void test() throws IOException {
		try(Engine volume = MapBuild.Build(path).createIfNotExist(true).clearOnOpen(false).exclusive(true).build()){
			int i = 1000;
			while(i-->0){
				volume.write("demo" + i, RandomString.next(32));
			}
			volume.forEach(kv->{ System.out.println(kv); });
			i = 1000;
			while(i-->0){
				if(i % 3 == 0) {
					volume.write("demo" + i, RandomString.next(1));
				}
			}
			volume.forEach(kv->{ System.out.println(kv); });
			i = 1000;
			while(i-->0){
				if(i % 2 == 0) {
					volume.delete("demo" + i);
				}
			}
			volume.forEach(kv->{ System.out.println(kv); });
		}
	}
	
	private static void bigTest() throws IOException {
		try(Engine volume = MapBuild.Build(path).createIfNotExist(true).clearOnOpen(false).exclusive(true).build()){
			int i = 1000000;
			while(i-->0){
				if(i% 10000 == 0) { System.out.println(i); }
				volume.write("bigdata" + i, RandomString.next(32));
			}
		}
	}
	
	private static void delete() throws IOException {
		try(Engine volume = MapBuild.Build(path).createIfNotExist(true).clearOnOpen(false).exclusive(true).build()){
			int i = 1000000;
			while(i-->0){
				if(i% 2 == 0 || i > 50000) {
					volume.delete("bigdata" + i);
					if(i% 10000 == 0) { System.out.println(i); }
				}
			}
		}
	}
	
	private static void iterator() throws IOException {
		try(Engine volume = MapBuild.Build(path).createIfNotExist(true).clearOnOpen(false).exclusive(true).build()){
			volume.forEach(kv->{
				System.out.println(kv);
			});
		}
	}
	
	private static void read() throws IOException {
		try(Engine volume = MapBuild.Build(path).createIfNotExist(true).clearOnOpen(false).exclusive(true).build()){
			int i = 1100;
			while(i-->0){
				System.out.println(volume.read("bigdata" + i));
			}
		}
	}
	
	private static void rebuild() throws IOException {
		File dataFile = new File(path + "/data");
		File offsetFile = new File(path + "/offset");
		File rebuildFile = new File(path + "/data.rebuild");
		dataFile.renameTo(rebuildFile);
		offsetFile.delete();
		dataFile.delete();
		DiskEngine.rebuildByData(new File(path), rebuildFile);
		rebuildFile.delete();
	}
	
	private static void threadTest() throws IOException, InterruptedException {
		ExecutorService pool = Executors.newFixedThreadPool(10);
		List<Callable<Void>> list = new ArrayList<Callable<Void>>();
		try(final Engine volume = MapBuild.Build(path).createIfNotExist(true).clearOnOpen(true).exclusive(true).build()){
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { volume.write("demo1" + i, RandomString.next(32)); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { volume.write("demo2" + i, RandomString.next(32)); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { volume.write("demo3" + i, RandomString.next(32)); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { volume.write("demo4" + i, RandomString.next(32)); }
					i = 10000;
					while(i-->0) { volume.read("demo4" + i); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { volume.write("demo5" + i, RandomString.next(32)); }
					return null;
				}
			});
			
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { System.out.println(volume.read("demo1" + i)); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { System.out.println(volume.read("demo2" + i)); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { System.out.println(volume.read("demo3" + i)); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { System.out.println(volume.read("demo4" + i)); }
					return null;
				}
			});
			list.add(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					int i = 10000;
					while(i-->0) { System.out.println(volume.read("demo5" + i)); }
					return null;
				}
			});
			List<Future<Void>> futures = pool.invokeAll(list);
			futures.forEach(f->{
				try {
					f.get();
				} catch (Exception e) {
					e.printStackTrace();
				}
			});
			pool.shutdown();
		}
	}
}
